import java.util.*;

/**
 * A node in the game. 
 */
public class GameNode {
    final static int TEXT_SELECTION = 0;
    final static int TEXT_ANSWER = 1;
    final static int IMAGE_SELECTION = 3;
    final static int DESCRIPTION_TEXT = 4;
    final static int DESCISION_POINT = 5;
    final static int END_POINT = 6;

    final static int END_NODE = 0;
    final static int START_NODE = 1;
    final static int GAME_NODE = 2;

    /* The title or the question.  */
    private String heading;
    /* taskType can be END_NODE, START_NODE or GAME_NODE.  */
    private int taskType;
    private Vector possibleSolutions = new Vector();
    /** Maximum score in this node. */
    private int maxScore;
    /** Has the used chosen a right answer? */
    private boolean finished;
    /** The type can be TEXT_SELECT, TEXT_ANSWER or IMAGE_SELECTION. */    
    private int nodeType;
    /** The already reached score. In the beginning it is the highest possible (it is
		equal to maxScore) and it decreases with wrong answers. */
    private int score;
    private String nodeId = null;
	/** The standard malus currently only used in TEXT_ANSWER nodes
	 * for wrong answers.  */
	private int standardMalus = 0;
	private GameNode lastNode = null;
	/* Src of a medium within a GameNode*/
    private String medium = null;
	/* text of a hint within a GameNode*/
    private String hint = null;
    
    // TODO: Vector of media stuff like pictures.

    GameNode() {
		this("Node without a name", null, TEXT_SELECTION, 0);
    }
	
    GameNode(String title) {
		this(title, null, TEXT_SELECTION, 0);
    }
	
    GameNode(String title, String id) {
		this(title, id, TEXT_SELECTION, 0);
    }
	
    GameNode(String title, int taskType, int maxScore) {
		this(title, null, taskType, maxScore);
    }
	
    GameNode(String title, String id, int taskType, int maxScore) {
		setTitle(title);
		setTaskType(taskType);
		setMaxScore(maxScore);
		setId(id);
		this.finished = false;
		this.nodeType = GAME_NODE;
    }
	
    GameNode(String title, int taskType) {
		this(title, null, taskType, 0);
    }
	
    int getNodeType() {
		return this.nodeType;
    }
	
    boolean isEndNode() {
		return this.nodeType == END_NODE;
    }
	
    boolean isStartNode() {
		return this.nodeType == START_NODE;
    }
	
    void setEndNode() {
		this.nodeType = END_NODE;
    }
	
    public void setStartNode() {
		this.nodeType = START_NODE;
    }
	
    /* Returns the nodes title (means the displayed question). */
    public String toString() {
    	 return this.heading;
    }
	
    /*
     * The title is the question.
     */
    public void setTitle(String heading) {
		this.heading = heading;
    }

    public void setMedium(String medium){
        this.medium = medium;
    }
    
    public String getMedium(){
        return this.medium;
    }

    public void setHint(String hint){
        this.hint = hint;
    }
    
    public String getHint(){
        return this.hint;
    }

    /* 
     * Can be END_NODE, START_NODE or GAME_NODE.  
     * There should only be one START_NODE and there must be
     * be one START_NODE if you don't want undefined behaviour.
     */
    public void setTaskType(int taskType) {
		this.taskType = taskType;
    }
    
    public void addSolution(Solution s) {
		this.possibleSolutions.addElement(s);
    }
    
    public int getTaskType() {
		return this.taskType;
    }
    
	/** 
	 * Sets the maximal reachable score.
	 */
    public void setMaxScore(int maxScore) {
		this.maxScore = maxScore;
		this.score = maxScore;
    }

    public void decreaseScore(int subScore) {
		System.out.println("Max reachable score in <" + this + "> is " + score + ".");
		this.score -= subScore;
		if (score < 0) {
			score = 0;
		}
		if (subScore > 0) {
			System.out.println("Max reachable score in <" + this + "> is now decreased to " + score);
		}
    }
	
    /** 
     * Returns the actual score. In the beginning this is equal to
     * maxScore and maybe decreases after that.
     */
    public int getScore() {
		return this.score;
    }

	public int getMaxScore() {
		return this.maxScore;
	}
	
    /**
     * Returns a specific solution of this node by its index.
	 * index of -1 means a general wrong Solution.
     */
    public Solution getSolution(int index) {
		if (index == -1)
			return new Solution("Wrong Solution", standardMalus);
		else
			return (Solution) this.possibleSolutions.elementAt(index);
    }

	public void setStandardMalus(int standardMalus) {
		this.standardMalus = standardMalus;
	}
	
    /**
     * Has the user already answered the right question?
     */
    public boolean isFinished() {
		return this.finished;
    }
	
    /**
     * Use this after a used chose the right solution and got his score.
     */
    public void setFinished() {
		this.finished = true;
    }
    
    /**
     * Run this when a player chooses a solution with index index.  
     * Returns the following GameNode, which is null in the case of
     * a wrong solution.
     * A wrong solution decreases the possible users score.
	 * index == -1 means a general wrong Solution.
     */
    public GameNode chooseSolution(int index) {
		Solution chosen = getSolution(index);
		System.out.println("The chosen solution is called <" + chosen + ">.");
		decreaseScore(chosen.getMalus());
		return chosen.getTargetNode();
    }

	
    /**
     * Returns the number of the solutions.
     */
    public int getSolNo() {
		return this.possibleSolutions.size();
    }
	
    public String getSolName(int index) {
		return (String) this.possibleSolutions.elementAt(index).toString();
    }
    
    public void setId(String id) {
		this.nodeId = id;
    }
	
    public String getid() {
		return this.nodeId;
    }
	
    /**
     * Returns the target node (to which it links) of a specific solution.
     */
    public GameNode getSolTargetNode(int index) {
		return ((Solution)(possibleSolutions.elementAt(index))).getTargetNode();
    }
	
    /**
     * Returns the source file (pic, mpeg, etc.) of Solution number index.
     */
    public String getSourceFile(int index) {
		return getSolution(index).getSourceFile();
    }

	public GameNode getLastNode() {
		return lastNode;
	}

	public void setLastNode(GameNode lastNode) {
		this.lastNode = lastNode;
	}
}